#include "stdafx.h"
#include <iostream>
#include <time.h>
#include <Windows.h>
#include "events.h"
using namespace std;

events::events(void)
{
	int i = 0;
	int node;
	int flag;
	element* index = NULL;
	element* check = NULL;

	head = NULL;
	srand(time(NULL));
	for(i=0;i<NUM_OF_TEST_CASE;i++)
	{
		flag = 0;
		while(flag == 0)
		{
			node = rand() % MAX_NODE_NUMBER;
			check = head;
			while(check != NULL)
			{
				if(check->nodeID == node)
					break;
				else
					check = check->next;	
			}
			if(check == NULL)
				flag = 1;
			if(flag == 1)
			{
				if(head == NULL)
				{
					head = new element;
					head->nodeID = node;
					head->clock = rand()%100+1;
					head->on = 0;
					head->eventType = EventType::NODE_EVENT;

					head->next = new element;
					head->next->nodeID = node;
					head->next->clock = head->clock + rand()%100+1;
					index = head->next;
					index->on = 1;
					index->next = NULL;
					index->eventType = EventType::NODE_EVENT;

					tail = index;
				}
				else
				{
					index->next = new element;
					index = index->next;
					index->nodeID = node;
					index->clock = rand()%100;
					index->on = 0;
					index->eventType = EventType::NODE_EVENT;

					index->next = new element;
					index->next->nodeID = node;
					index->next->clock = index->clock + rand()%100+1;
					index = index->next;
					index->on = 1;
					index->next = NULL;
					index->eventType = EventType::NODE_EVENT;

					tail = index;
				}
			}
		}
	}

	// initialize a message event so we can start from that
	index->next = new element;
	index = index->next;

	index->clock = 50; // rand() % 100 + 1;
	index->nodeID = 1;
	index->eventType = EventType::SEND_EVENT;
	index->next = NULL;
	index->on = 1;

	index->message = new messageInfo;
	index->message->messageID = 1;
	index->message->messageTimestamp = rand() % 100 + 1;
	index->message->senderID = 1;
	index->message->recipientID = 100;

	tail = index;
	nodesReceivedMessage = 0;
}

events::~events(void)
{
	thisGraph.~graph();
}

void events::sort()
{
	int record;
	element *prev;
	element *index;
	element *large;
	element *temp = NULL;

	while(head != NULL)
	{
		record = head->clock;
		large = head;
		index = head;
		while(index->next != NULL)
		{
			if(index->next->clock > record)
			{
				record = index->next->clock;
				large = index;
			}
			else if(index->next->clock == record)
			{
				if(index->next->nodeID < large->next->nodeID)
				{
					record = index->next->clock;
					large = index;
				}
			}
			index = index->next;
		}
		if(temp == NULL)
		{
			temp = large->next;
			large->next = large->next->next;
			temp->next = NULL;
		}
		else
		{
			if(large == head && large->clock == record)
			{
				index = large;
				head = head->next;
				index->next = temp;
				temp = index;
			}
			else
			{
				index = large->next;
				large->next = large->next->next;
				index->next = temp;
				temp = index;
			}
		}
	}
	head = temp;
}

int events::simulate(graph *sim, int t, int *thisNodeID)
{
	element *index;
	int flag = -1;
	int sendMessageThreshold;
	int sendTime, recvTime;
	node senderNode, recipientNode;

	//if(head == NULL){		// no more event is queued
	//	cout << "no more event is queued!" << endl;
	//	return -2;
	//}

	if(t >= head->clock)
	{
		flag = 1;
		switch(head->eventType){
		case EventType::NODE_EVENT:
			if(head->on == 1)
			{
				cout << "time " << t << ": " << head->nodeID << " joins" << endl;
				flag = 1;
			}
			if(head->on == 0)
			{
				cout << "time " << t << ": " << head->nodeID << " leaves" << endl;
				flag = 0;
			}
			break;
		case EventType::SEND_EVENT:
			senderNode = sim->getNode(head->nodeID - 1);
			if(senderNode.on){
				senderNode.message->messageTimestamp = t;
				//senderNode.message->messageID = global::messageID;

				for(int i = 0; i < senderNode.neighbor_number; i++){//->next != NULL){
					if(sim->wantsToSendMessage(senderNode, rand() % 100 / (float)100)){
						//senderNode.message->senderID = senderNode.ID;
						//senderNode.message->recipientID = senderNode.recipientList->nodeID;
						//senderNode.message->channelNumber = sim->getChannelUsed(senderNode, rand() % 100 / (float) 100);
						//sim->send(senderNode.ID, senderNode.message);

					
					
						element *recvEvent = new element;
						recvEvent->eventType = RECV_EVENT;
						recvEvent->message = new messageInfo;
						recvEvent->message->senderID = senderNode.ID;
						recvEvent->message->recipientID = senderNode.recipientList->nodeID;
						recvEvent->message->channelNumber = sim->getChannelUsed(senderNode, rand() % 100 / (float) 100);
						recvEvent->message->messageID = senderNode.message->messageID;
						recvEvent->message->hasRead = false; 
					
						recvTime = senderNode.message->messageTimestamp + 
							sim->getSendDelay(senderNode.message->channelNumber, senderNode) + 
							sim->getTransmissionDelay(recvEvent->message->channelNumber, sim->getNode(senderNode.ID), sim->getNode(senderNode.recipientList->nodeID));

						//cout << "time " << t << ": send: (" << senderNode.ID << ") --> " << 
						//	senderNode.recipientList->nodeID << " via channel " << recvEvent->message->channelNumber <<
						//	", should arrive at time: " << recvTime << endl;

						recvEvent->clock = recvTime;
						recvEvent->message->messageTimestamp = recvTime;

						recvEvent->nodeID = senderNode.recipientList->nodeID;
						recvEvent->on = 1;
						recvEvent->next = NULL;
						insertEventAtTimeT(recvTime, recvEvent);
					
					}
					if(senderNode.recipientList->next != NULL)		// keep shifting to next neighbor if there is one
						senderNode.recipientList = senderNode.recipientList->next;
				}
			}else{		// if senderNode is offline: sender will skip this send event and 
				cout << "time " << t << ": send: (" << senderNode.ID << ") --> " << 
					senderNode.recipientList->nodeID << ": " <<
					" sender is not online, send event skipped" << endl;
				senderNode.hasSentTheSameMessage = false;
				sim->setNode(senderNode);
			}
			break;

		// in recv event it's much simpler. we grab the message from queue to our virtual holder when it arrives,
		// and add with recv delay defined by each user, and incoporate the message into the send event 
		// and queue it into our event queue.
		case EventType::RECV_EVENT:
			recipientNode = sim->getNode(head->nodeID - 1);

			if(recipientNode.on){
				recipientNode.message = head->message;
			
				sendTime = t + 
					sim->getRecvDelay(recipientNode.message->channelNumber, recipientNode);
			
				if(!recipientNode.hasSentTheSameMessage){
					//cout << "time " << t << ": recv: " << recipientNode.message->senderID << " --> (" << 
					//	 recipientNode.ID << ") via channel " << recipientNode.message->channelNumber <<
					//	". send again at time: " << sendTime << endl;
					
					element *sendEvent = new element;
					sendEvent->clock = sendTime;
					sendEvent->eventType = SEND_EVENT;
					sendEvent->message = new messageInfo;
					sendEvent->message->senderID = recipientNode.ID;
					sendEvent->message->messageTimestamp = sendTime;
					sendEvent->message->messageID = recipientNode.message->messageID;
					sendEvent->nodeID = recipientNode.ID;
					sendEvent->on = 1;
					sendEvent->next = NULL;
					insertEventAtTimeT(sendTime, sendEvent);

					recipientNode.message->hasRead = true;
					recipientNode.hasSentTheSameMessage = true;
					sim->setNode(recipientNode);

					nodesReceivedMessage++;
					if(nodesReceivedMessage == MAX_NODE_NUMBER*0.01)
						cout << "Time: " << t << " 1% of nodes: " << nodesReceivedMessage << " received message" << endl;
					if(nodesReceivedMessage == MAX_NODE_NUMBER*0.02)
						cout << "Time: " << t << " 2% of nodes: " << nodesReceivedMessage << " received message" << endl;
					if(nodesReceivedMessage == MAX_NODE_NUMBER*0.03)
						cout << "Time: " << t << " 3% of nodes: " << nodesReceivedMessage << " received message" << endl;
					if(nodesReceivedMessage == MAX_NODE_NUMBER*0.04)
						cout << "Time: " << t << " 4% of nodes: " << nodesReceivedMessage << " received message" << endl;
					if(nodesReceivedMessage == MAX_NODE_NUMBER*0.05)
						cout << "Time: " << t << " 5% of nodes: " << nodesReceivedMessage << " received message" << endl;
					if(nodesReceivedMessage == MAX_NODE_NUMBER*0.06)
						cout << "Time: " << t << " 6% of nodes: " << nodesReceivedMessage << " received message" << endl;
					if(nodesReceivedMessage == MAX_NODE_NUMBER*0.07)
						cout << "Time: " << t << " 7% of nodes: " << nodesReceivedMessage << " received message" << endl;
					if(nodesReceivedMessage == MAX_NODE_NUMBER*0.08)
						cout << "Time: " << t << " 8% of nodes: " << nodesReceivedMessage << " received message" << endl;
					if(nodesReceivedMessage == MAX_NODE_NUMBER*0.09)
						cout << "Time: " << t << " 9% of nodes: " << nodesReceivedMessage << " received message" << endl;
					if(nodesReceivedMessage == MAX_NODE_NUMBER*0.1)
						cout << "Time: " << t << " 10% of nodes: " << nodesReceivedMessage << " received message" << endl;
					if(nodesReceivedMessage == MAX_NODE_NUMBER*0.2)
						cout << "Time: " << t << " 20% of nodes: " << nodesReceivedMessage << " received message" << endl;
					if(nodesReceivedMessage == MAX_NODE_NUMBER*0.3)
						cout << "Time: " << t << " 30% of nodes: " << nodesReceivedMessage << " received message" << endl;
					if(nodesReceivedMessage == MAX_NODE_NUMBER*0.4)
						cout << "Time: " << t << " 40% of nodes: " << nodesReceivedMessage << " received message" << endl;
					if(nodesReceivedMessage == MAX_NODE_NUMBER*0.5)
						cout << "Time: " << t << " 50% of nodes: " << nodesReceivedMessage << " received message" << endl;
					if(nodesReceivedMessage == MAX_NODE_NUMBER*0.6)
						cout << "Time: " << t << " 60% of nodes: " << nodesReceivedMessage << " received message" << endl;
					if(nodesReceivedMessage == MAX_NODE_NUMBER*0.7)
						cout << "Time: " << t << " 70% of nodes: " << nodesReceivedMessage << " received message" << endl;
					if(nodesReceivedMessage == MAX_NODE_NUMBER*0.8)
						cout << "Time: " << t << " 80% of nodes: " << nodesReceivedMessage << " received message" << endl;
					if(nodesReceivedMessage == MAX_NODE_NUMBER*0.9)
						cout << "Time: " << t << " 90% of nodes: " << nodesReceivedMessage << " received message" << endl;
					//if(nodesReceivedMessage > 200)
						//cout << "***" << nodesReceivedMessage << "***" << endl;
				}else{
					//cout << "time " << t << ": recv: " << recipientNode.message->senderID << " --> (" << 
					//	recipientNode.ID << ") via channel " << recipientNode.message->channelNumber <<
					//	". msg received before." << endl;
				}
			}else{		// if the recipient is not online, we will sent to his/her mail inbox
				cout << "time " << t << ": recv: node" << 
						recipientNode.ID <<
						". recipient is not online." << endl;
				recipientNode.message = head->message;
				recipientNode.message->hasRead = false;
				recipientNode.hasSentTheSameMessage = false;
			}
			//free(&recipientNode);
			break;
		}
		//}
		//else{			// SENDING OR RECVING MESSAGE
		//	graph::messageInfo *messageInfo = new graph::messageInfo();
		//	messageInfo->messageID = 1;
		//	messageInfo->messageTimestamp = global::timeNow;
		//	messageInfo->recipient = ;
		//	messageInfo->sender = 
		//	
		//	if(head->type == EventType::SEND_EVENT){
		//		thisGraph.send(head->nodeID, head->message);
		//	}
		//}
		*thisNodeID = head->nodeID;
		index = head;
		head = head->next;
		free(index);
	}

	return flag;
}

bool events::insertEventAtTimeT(int thisTime, element *targetElement)
{
	element *index = head;

	if(index->clock > targetElement->clock){
		targetElement->next = index;
		head = targetElement;
	}else{
		do{
			if(index->next == NULL){
				index->next = targetElement;
				break;
			}
			if(index->next->clock > targetElement->clock){
				targetElement->next = index->next;
				index->next = targetElement;
				break;
			}else{
				index = index->next;
			}
		}while(index->next != NULL);
	}
	return true;
}

bool events::removeHead(int thisTime, element *targetElement)
{
	free(head);
	head = targetElement;
	return true;
}

void events::info()
{
	element *index = head;

	while(index != NULL)
	{
		cout << "ID: " << index->nodeID << endl;
		cout << "Clock: " << index->clock << endl;
		cout << "On: " << index->on << endl; 
		cout << endl;
		index = index->next;
	}
}